#!/usr/bin/env bash

################################################################################
# Runs multiple checks.
#
# The default set of checks most closely matches the tests run during
# a continuous integration test, however these do not match perfectly
# since those tests run on different architectures and environments.
#
# Defaults to the following tests:
#   pylint
#   mypy
#   format-incremental
#   pytest-and-incremental-coverage
#   doctest
#
# Usage:
#     check/all revision [BASE_REVISION] [--only-changed-files] [--apply-format-changes]
#
# BASE_REVISION is forwarded to format-incremental and to the pytest and pylint
# checks (pytest-and-incremental-coverage or pytest-changed-files and
# pylint-changed-files). See those checks for how to specify this value.
#
# If --only-changed-files is specified, pytest-changed-files will be run
# instead of pytest-and-incremental-coverage, and pylint-changed-files will
# be run instead of pylint.
#
# If --apply-format-changes is specified the --apply flag will be passed
# to format-incremental to apply the format changes suggested by the
# formatter.
################################################################################

# Get the working directory to the repo root.
thisdir=$(dirname "${BASH_SOURCE[0]:?}") || exit $?
repo_dir=$(git -C "${thisdir}" rev-parse --show-toplevel) || exit $?
cd "${repo_dir}" || exit $?

errors=()

# Parse arguments.
apply_arg=( )
only_changed=0
rev=( )
for arg in "$@"; do
    if [[ "${arg}" == "--only-changed-files" ]]; then
        only_changed=1
    elif [[ "${arg}" == "--apply-format-changes" ]]; then
        apply_arg=( "--apply" )
    elif [[ "${#rev[@]}" == 0 ]]; then
        if [ "$(git cat-file -t "${arg}" 2> /dev/null)" != "commit" ]; then
            echo -e "\033[31mNo revision '${arg}'.\033[0m" >&2
            exit 1
        fi
        rev=( "${arg}" )
    else
        echo -e "\033[31mInvalid arguments. Expected [BASE_REVISION] [--only-changed-files] [--apply-format].\033[0m" >&2
        exit 1
    fi
done

echo "Running misc"
check/misc || errors+=( "check/misc failed" )

if [ ${only_changed} -ne 0 ]; then
  echo "Running incremental pylint"
  check/pylint-changed-files || errors+=( "check/pylint-changed-files failed" )
else
  echo "Running pylint"
  check/pylint || errors+=( "check/pylint failed" )
fi

echo "Running mypy"
check/mypy || errors+=( "check/mypy failed" )

echo "Running incremental format"
check/format-incremental "${rev[@]}" "${apply_arg[@]}" ||
    errors+=( "check/format-incremental failed" )

if [ ${only_changed} -ne 0 ]; then
    echo "Running pytest and incremental coverage on changed files"
    check/pytest-changed-files-and-incremental-coverage "${rev[@]}" ||
         errors+=( "check/pytest-changed-files-and-incremental-coverage failed" )
else
    echo "Running pytest and incremental coverage"
    check/pytest-and-incremental-coverage "${rev[@]}" ||
         errors+=( "check/pytest-and-incremental-coverage failed" )
fi

echo "Running doctest"
check/doctest || errors+=( "check/doctest failed" )

echo
if [[ "${#errors[@]}" == 0 ]]; then
    echo "All checks passed."
    result=0
else
    printf "Some checks failed.\n\n"
    printf "  %s\n" "${errors[@]}"
    result=1
fi

exit "${result}"
